/*----------------------------------------------------------------------------
Owner(s): Shane Whitfield
$Copyright: $
$Id: $
----------------------------------------------------------------------------*/

#include "go_mobiles.h"
#include "timermgr.h"
#include "go_playerunits.h"
#include "render.h"
#include "mathutils.h"

/*--------------------------------------------------------------------------*/
CGoMobile::CGoMobile()
{
	m_state = EState_Stopped;
	m_velocity = Vector2f::Zero;
	memset(&m_followState, 0, sizeof(m_followState));
	m_pathSpeed = 0.0f;
}

void CGoMobile::SetSpeed(float i_speed)
{
	m_velocity.Normalize();
	m_velocity *= i_speed;
}

void CGoMobile::SetPath(const CGoPath* i_path)
{
	m_path = i_path;
	
	if(m_path)
	{
		m_path->Init(m_followState);
		setState(EState_FollowingPath);
	}
#if DEBUG
	else
	{
		printf("Error: no path passed in to set path!");
	}
#endif // DEBUG
}

void CGoMobile::Update()
{	
	super::Update();
	
	for(;;)
	{
		EState prevState = m_state;
		switch(m_state)
		{
		case EState_Moving:
			{
				if (!shouldBeMoving())
				{
					setState(EState_Stopped);
				}
				else
				{
					//update the position by the velocity.
					SetPos((m_velocity * Dt()) + GetPos());
				}
			}
			break;
		case EState_FollowingPath:
			{
				bool isAtPathEnd = m_path->Advance(m_followState, m_pathSpeed * Dt());
				
				//match the position on the path
				SetPos(m_followState.GetPos());
				
				if (isAtPathEnd)
				{
					setState(EState_Stopped);
				}
			}
			break;
		case EState_Stopped:
			{
				if (shouldBeMoving())
				{
					setState(EState_Moving);
				}
			}
			break;
		}
		
		if (prevState == m_state)
		{
			break;
		}
	}
}

void CGoMobile::setState(EState i_state)
{
	m_state = i_state;
}

/*--------------------------------------------------------------------------*/

CGoHealer::CGoHealer()
{
	m_healTarget = NULL;
	m_healingRange = 0.1f;
	m_maxHealingEnergy = 30.0f;
	m_curHealingEnergy = m_maxHealingEnergy;
	
	m_state = EState_WaitingInjury;
	
	SetBoundingRadius(0.05f);
	
	SetTexture("healer.png");
 
}

void CGoHealer::updateVelocityToCircleTarget()
{
	Vector2f velocity = m_healTarget->GetPos() - GetPos();
					
	//simple 2d dot
	float tmp = velocity.x ;
	velocity.x = velocity.y;
	velocity.y = -tmp;
					
	SetVelocity(velocity);
	SetSpeed(2.5f);
}

void CGoHealer::logState()
{
	switch (m_state)
		{
		case EState_WaitingInjury:
			{
				printf("WaitingInjury\n");
			}
			break;
		case EState_MovingToInjury:
			{
				printf("MovingToInjury\n");
			}
			break;
		case EState_HealingInjury:
			{
				printf("HealingInjury\n");
			}
			break;
		case EState_MovingHome:
			{
				printf("MovingHome\n");
			}
			break;
		}
}

void CGoHealer::Render()
{
	super::Render();
	
	if (m_state == EState_HealingInjury)
	{
		BasicDrawObjects::DrawSegment(GetPos(), m_healTarget->GetPos(), Color3f(0.1f, 1.0f, 0.1f));
	}
}

void CGoHealer::Update()
{
	super::Update();
	
	for(;;)
	{	
		//logState();
		EState prevState = m_state;
		
		if (!m_healStation->IsConnected())
		{
			setState(EState_MovingHome);
		}

		
		switch(m_state)
		{
		case EState_WaitingInjury:
			{
				//if the healer has a target.. start moving towards it
				if (m_healStation->IsConnected() && m_healTarget && !IsTargetHealed() && hasEnoughEnergyForNewTarget())
				{
					setState(EState_MovingToInjury);
				}
				else
				{
					replenishEnergy();
				}
			}
			break;
		case EState_MovingToInjury:
			{
				//is the target already fully healed?
				if (IsTargetHealed())
				{
					setState(EState_MovingHome);
				}
				else if (Dist(m_healTarget->GetPos(), GetPos()) < m_healingRange)
				{
					setState(EState_HealingInjury);
				}
			}
			break;
		case EState_HealingInjury :
			{
				if (IsTargetHealed() || m_healTarget->IsDead() || isEnergyEmpty())
				{
					setState(EState_MovingHome);
				}
				else
				{
					healTarget();
					updateVelocityToCircleTarget();
				}
			}
			break;
		case EState_MovingHome :
			{
				//we have a new target to heal!
				if (m_healStation->IsConnected() && m_healTarget && hasEnoughEnergyForNewTarget())
				{
					setState(EState_MovingToInjury);
				}
				else if (IsNear(m_healStation->GetPos(), GetPos(), GetBoundingRadius()))
				{
					setState(EState_WaitingInjury);
				}
			}
			break;
		}
		
		if (prevState == m_state)
		{
			break;
		}
	}	
}

void CGoHealer::healTarget()
{
	float healAmount = Dt() * 5.0f;
	
	//consume some energy
	m_curHealingEnergy = BBMIN(m_curHealingEnergy - healAmount, 0.0f);
	
	m_healTarget->Heal(healAmount);
}

void CGoHealer::replenishEnergy()
{
	if (isEnergyFull())
	{
		return;
	}
	
	float energyReplenished= Dt() * 2.0f;
	
	m_curHealingEnergy = BBMIN(m_curHealingEnergy + energyReplenished, m_maxHealingEnergy);
}

void CGoHealer::setState(EState i_state)
{
	m_state = i_state;
	
	switch(m_state)
	{
	case EState_MovingToInjury :
		{
			SetVelocity(m_healTarget->GetPos() - GetPos());
			SetSpeed(1.0f);
		}
		break;
	case EState_MovingHome :
		{
			m_healTarget = NULL;
			SetVelocity(m_healStation->GetPos() - GetPos());
			SetSpeed(1.0f);
		}
		break;
	}
}


/*--------------------------------------------------------------------------*/

CGoMiner::CGoMiner()
{
	m_miningStation = NULL;
	m_miningTarget = NULL;
	m_miningRange = 0.1f;
	m_state = EState_WaitingSearchPing;
	
	SetBoundingRadius(0.05f);
	
	SetTexture("miner.png");
}

void CGoMiner::updateVelocityToCircleTarget()
{
	Vector2f velocity = m_miningTarget->GetPos() - GetPos();
					
	//simple 2d dot
	float tmp = velocity.x ;
	velocity.x = velocity.y;
	velocity.y = -tmp;
					
	SetVelocity(velocity);
	SetSpeed(2.5f);
}

void CGoMiner::Render()
{
	super::Render();
	
	
	if (m_state == EState_Mining)
	{
		BasicDrawObjects::DrawSegment(GetPos(), m_miningTarget->GetPos(), Color3f(0.1f, 1.0f, 0.1f));
	}
}

void CGoMiner::Update()
{
	super::Update();
	
	for(;;)
	{	
		//logState();
		EState prevState = m_state;
		
		if (!m_miningStation->IsConnected())
		{
			setState(EState_MovingHome);
		}
		
		switch(m_state)
		{
		case EState_WaitingSearchPing:
			{
				//if enough time has passed... ask for another target
				if (m_miningStation->IsConnected() && (T() - m_tState) >= 0.5f)
				{
					setState(EState_SearchingForMiningTarget);
				}
				
			}
			break;
		case EState_SearchingForMiningTarget:
			{
				if (m_miningStation->IsConnected() && m_miningTarget)
				{
					setState(EState_MovingToMinerals);
				}
				else
				{
					setState(EState_WaitingSearchPing);
				}
			}
			break;
		case EState_MovingToMinerals :
			{
				//is the target already fully healed?
				if (!m_miningTarget || m_miningTarget->IsEmpty())
				{
					setState(EState_MovingHome);
				}
				else if (Dist(m_miningTarget->GetPos(), GetPos()) < m_miningRange)
				{
					setState(EState_Mining);
				}
			}
			break;
		case EState_Mining :
			{
				if (!m_miningTarget || m_miningTarget->IsEmpty())
				{
					setState(EState_MovingHome);
				}
				else
				{
					m_miningTarget->Mine(10.0f * Dt());
					updateVelocityToCircleTarget();
				}
			}
			break;
		case EState_MovingHome:
			{
				if (IsNear(m_miningStation->GetPos(), GetPos(), GetBoundingRadius()))
				{
					setState(EState_SearchingForMiningTarget);
				}
			}
			break;
		}
		
		if (prevState == m_state)
		{
			break;
		}
	}	
}

void CGoMiner::setState(EState i_state)
{
	m_state = i_state;
	m_tState = T();
	
	switch(m_state)
	{
	case EState_SearchingForMiningTarget:
		{
			//ask our owner for a target in his range
			m_miningTarget = m_miningStation->GetClosestMiningTarget();
		}
		break;
	case EState_MovingToMinerals :
		{
			SetVelocity(m_miningTarget->GetPos() - GetPos());
			SetSpeed(1.0f);
		}
		break;
	case EState_MovingHome :
		{
			m_miningTarget = NULL;
			SetVelocity(m_miningStation->GetPos() - GetPos());
			SetSpeed(1.0f);
		}
		break;
	}
}


/*-----------------------------------EOF!-----------------------------------*/ 
